﻿using System;
using UnityEngine;
using System.Collections.Generic;

namespace winS.Unity
{
    /// <summary>
    /// Provides Random functions.
    /// this is a high-level wrapper for <see cref="UnityEngine.Random"/>.
    /// </summary>
    public static class Random
    {
        /// <summary>
        /// 正态分布随机
        /// </summary>
        public static NormalDistribution normalDistribution { get; } = new NormalDistribution();

        /// <summary>
        /// 设置随机种子
        /// </summary>
        public static void SetSeed(int randomSeed)
        {
            UnityEngine.Random.InitState(randomSeed);
        }
        /// <summary>
        /// 设置状态(随机种子)
        /// </summary>
        public static void SetState(UnityEngine.Random.State randomState)
        {
            UnityEngine.Random.state = randomState;
        }
        /// <summary>
        /// 获取状态(随机种子)
        /// </summary>
        public static UnityEngine.Random.State GetState()
        {
            return UnityEngine.Random.state;
        }

        /// <summary>
        /// 随机一个 <see cref="bool"/> 值
        /// </summary>
        public static bool Bool()
        {
            return Int(2) == 0;
        }
        /// <summary>
        /// 随机一个 [<paramref name="baseValue"/>-<paramref name="interval"/>, <paramref name="baseValue"/>+<paramref name="interval"/>] 的 <see cref="int"/> 值
        /// </summary>
        public static int Range(int baseValue, int interval)
        {
            return Int(baseValue - interval, baseValue + interval);
        }
        /// <summary>
        /// 随机一个值域为 [0,最大值) 的 <see cref="int"/> 值
        /// </summary>
        public static int Int(int maxValue)
        {
            return UnityEngine.Random.Range(0, maxValue);
        }
        /// <summary>
        /// 随机一个值域为 [最小值,最大值) 的 <see cref="int"/> 值
        /// </summary>
        public static int Int(int minValue, int maxValue)
        {
            return UnityEngine.Random.Range(minValue, maxValue);
        }
        /// <summary>
        /// 从 -1 和 1 中随机挑选一个
        /// </summary>
        public static int IntNormalized()
        {
            return 2 * Int(2) - 1;
        }

        /// <summary>
        /// 从区间内基于概率来随机获取一个值.
        /// <para>如果概率为1, 返回<paramref name="maxValue"/>;</para> 
        /// <para>如果概率为0, 返回<paramref name="minValue"/>;</para> 
        /// 如果概率为 (0, 1), 则按照轮盘赌策略来返回 (<paramref name="minValue"/>, <paramref name="maxValue"/>) 的值
        /// </summary>
        public static int GetValueBasedOnProbability(int minValue, int maxValue, float probability)
        {
            int result = minValue;
            int length = maxValue - minValue;
            for (int i = 0; i < length; i++) if (Float01() <= probability) result++;
            return result;
        }
        /// <summary>
        /// 随机选数.
        /// 从区间 [<paramref name="minValue"/>, <paramref name="maxValue"/>] 内挑选 <paramref name="count"/> 个数
        /// </summary>
        public static int[] SelectNumber(int minValue, int maxValue, int count)
        {
            int length = maxValue - minValue + 1;
            if (count > length) throw new Exception($"{nameof(Random)}.{nameof(SelectNumber)}: {nameof(count)} 不能超过区间范围");
            int[] ap = new ArithmeticProgressionInt(minValue, 1).ToArray(length);
            int[] result = new int[count];
            for (int i = 0; i < count; i++)
            {
                int randomIndex = Int(length);
                result[i] = ap[randomIndex];
                ap[randomIndex] = ap[--length];
            }
            return result;
        }
        ///// <summary>
        ///// 随机选取.
        ///// 从指定的集合 <paramref name="list"/> 中随机选取 <paramref name="selectionNumber"/> 个元素
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="list">要选取的集合</param>
        ///// <param name="selectionNumber">要从集合中获取的元素数量</param>
        ///// <returns></returns>
        //public static T[] RandomSelection<T>(IList<T> list, int selectionNumber)
        //{
        //    int length = list.Count;
        //    if (length == 0) return null;
        //    if (selectionNumber > length) throw new Exception($"{nameof(Random)}.{nameof(RandomSelection)}: 随机选择的数量超过了可选择的最大数量!");
        //    int[] indexs = new int[length];
        //    for (int i = 0; i < length; i++) indexs[i] = i;
        //    T[] result = new T[selectionNumber];
        //    for (int i = 0; i < selectionNumber; i++)
        //    {
        //        int index = Int(length);
        //        result[i] = list[indexs[index]];
        //        indexs[index] = indexs[--length];
        //    }
        //    return result;
        //}
        //public static List<T> RandomSelection<T>(IList<T> selectionObjects, int selectionNumber, Func<T, List<T>, bool> selectFunc)
        //{
        //    T[] selectionObjectsArray = selectionObjects.ToArray();
        //    int length = selectionObjectsArray.Length;
        //    if (length == 0) return null;
        //    if (selectionNumber > length) throw new Exception("[Random.RandomSelection] Error : selectionNumber > Number of allSelectionObject!");
        //    int[] objectIndexes = new int[length];
        //    for (int i = 0; i < length; i++) objectIndexes[i] = i;
        //    List<T> result = new List<T>(selectionNumber);
        //    int selectedNumber = 0;
        //    while (selectedNumber < selectionNumber)
        //    {
        //        if (length == 0) throw new Exception("[Random.RandomSelection] Number of available objects less selectionNumber,Please reduce selectionNumber or relax selectFunc!");
        //        int randomIndex = Int(length);
        //        int objectIndex = objectIndexes[randomIndex];
        //        T selectionObject = selectionObjectsArray[objectIndex];
        //        if (selectFunc(selectionObject, result))
        //        {
        //            selectedNumber++;
        //            result.Add(selectionObject);
        //        }
        //        objectIndexes[randomIndex] = objectIndexes[--length];
        //    }
        //    return result;
        //}
        /// <summary>
        /// 随机选择一个元素
        /// </summary>
        public static T Pick<T>(IList<T> list)
        {
            return list[Int(list.Count)];
        }
        /// <summary>
        /// 从 <paramref name="object1"/> 和 <paramref name="object2"/> 中随机挑选一个
        /// </summary>
        public static T Pick<T>(T object1, T object2)
        {
            return Int(2) == 0 ? object1 : object2;
        }
        /// <summary>
        /// 洗牌.
        /// 保证每个元素都不在原来的位置上
        /// </summary>
        /// <param name="list">要进行洗牌操作的集合</param>
        public static void Shuffle<T>(IList<T> list)
        {
            for (int i = list.Count - 1; i > 0; i--)
            {
                int swapIndex = Int(i);
                (list[i], list[swapIndex]) = (list[swapIndex], list[i]);
            }
        }

        /// <summary>
        /// 随机一个以 <see cref="UnityEngine.Vector3"/> 表示的三维向量
        /// </summary>
        public static Vector3 Vector3(float minValue, float maxValue)
        {
            return new Vector3(Float(minValue, maxValue), Float(minValue, maxValue), Float(minValue, maxValue));
        }
        /// <summary>
        /// 随机一个以 <see cref="UnityEngine.Vector2"/> 表示的二维向量
        /// </summary>
        public static Vector2 Vector2(float minValue, float maxValue)
        {
            return new Vector2(Float(minValue, maxValue), Float(minValue, maxValue));
        }
        /// <summary>
        /// 随机一个以 <see cref="UnityEngine.Vector3"/> 表示的三维方向
        /// </summary>
        public static Vector3 Direction()
        {
            return Vector3(-1f, 1f).normalized;
        }
        /// <summary>
        /// 随机一个以 <see cref="UnityEngine.Vector2"/> 表示的二维方向
        /// </summary>
        public static Vector2 Direction2D()
        {
            return Vector2(-1f, 1f).normalized;
        }
        public static Vector3 Direction(Vector3 startDirection, float maxAngle, Vector3 axis)
        {
            float randomAngle = Float(-maxAngle, maxAngle);
            return Quaternion.AngleAxis(randomAngle, axis) * startDirection;
        }
        /// <summary>
        /// 从 <paramref name="startDirection"/> 和 <paramref name="endDirection"/> 组成的插值区间中随机选取一个 <see cref="UnityEngine.Vector3"/> 方向
        /// </summary>
        public static Vector3 RandomDirection(Vector3 startDirection, Vector3 endDirection)
        {
            return UnityEngine.Vector3.Lerp(startDirection, endDirection, UnityEngine.Random.value).normalized;
        }
        /// <summary>
        /// 从 <paramref name="startDirection"/> 和 <paramref name="endDirection"/> 组成的插值区间中随机选取一个 <see cref="UnityEngine.Vector2"/> 方向
        /// </summary>
        public static Vector2 RandomVector2Direction(Vector2 startDirection, Vector2 endDirection)
        {
            return UnityEngine.Vector2.Lerp(startDirection, endDirection, UnityEngine.Random.value).normalized;
        }
        public static Vector2 RandomVector2Direction(Vector2 startDirection, float maxAngle)
        {
            float randomAngle = Float(-maxAngle, maxAngle);
            return Quaternion.AngleAxis(randomAngle, UnityEngine.Vector3.forward) * startDirection;
        }


        /// <summary>
        /// 随机一个 [<paramref name="baseValue"/>-<paramref name="interval"/>, <paramref name="baseValue"/>+<paramref name="interval"/>] 的 <see cref="float"/> 值
        /// </summary>
        public static float Range(float baseValue, float interval)
        {
            return Float(baseValue - interval, baseValue + interval);
        }
        /// <summary>
        /// 随机一个 [0, 1] 的 <see cref="float"/> 值
        /// </summary>
        public static float Float01()
        {
            return UnityEngine.Random.value;
        }
        /// <summary>
        /// 随机一个值域为 [0, <paramref name="maxValue"/>] 的 <see cref="float"/> 值
        /// </summary>
        public static float Float(float maxValue)
        {
            return UnityEngine.Random.Range(0f, maxValue);
        }
        /// <summary>
        /// 随机一个值域为 [<paramref name="minValue"/>, <paramref name="maxValue"/>] 的 <see cref="float"/> 值
        /// 
        /// </summary>
        public static float Float(float minValue, float maxValue)
        {
            return UnityEngine.Random.Range(minValue, maxValue);
        }
        /// <summary>
        /// 随机一个值域为 [-1,1] 的 <see cref="float"/> 值
        /// </summary>
        public static float FloatNormalized()
        {
            return UnityEngine.Random.Range(-1f, 1f);
        }

        /// <summary>
        /// 随机一个在 <paramref name="camera"/> 视锥体中的点
        /// </summary>
        public static Vector3 RandomPointInViewFrustum(Camera camera)
        {
            float nearPlaneDistance = camera.nearClipPlane;
            float farPlaneDistance = camera.farClipPlane;
            float zDistance = Float(nearPlaneDistance, farPlaneDistance);
            float scale = Math.Remap(zDistance, nearPlaneDistance, farPlaneDistance, 0f, 1f);
            float tanValue = Math.TanDeg(camera.fieldOfView * 0.5f);
            float halfHeightNear = tanValue * nearPlaneDistance;//半近平面高度
            float halfHeightFar = tanValue * farPlaneDistance;//半远平面高度
            float halfY = Math.Lerp(halfHeightNear, halfHeightFar, scale);//Y轴取值范围
            float yDistance = Float(-halfY, halfY);
            float halfWidthNear = halfHeightNear * camera.aspect;//半近平面宽度
            float halfWidthFar = halfHeightFar * camera.aspect;//半远平面宽度
            float halfX = Math.Lerp(halfWidthNear, halfWidthFar, scale);
            float xDistance = Float(-halfX, halfX);
            Transform cameraTransform = camera.transform;
            return cameraTransform.position + cameraTransform.right * xDistance + cameraTransform.up * yDistance + cameraTransform.forward * zDistance;
        }
    }
}